﻿/* 
 Simplified implementation of IEquatable
 GetHashCode is used to determine whether the two objects are equal
 So base object implements IEquatable<BaseObject> to full extent
 including overloading operators == and != and Equals(object obj) inherited from object
 But all derived classes just override the GetHashCode to include the extra field they might have
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IdeaNMR.Web.Core
{
    public partial class HardObject
    {
        public override int GetContentHashCode()
        {
            int result = base.GetContentHashCode();
            if (this.ContactPerson != null)
                result ^= this.ContactPerson.GetHashCode();
            if (this.ContactEmail != null)
                result ^= this.ContactEmail.GetHashCode();
            if (this.Location != null)
                result ^= this.Location.GetHashCode();
            return result;
        }
    }

    public partial class Sample
    {
        public override int GetContentHashCode()
        {
            int result = base.GetContentHashCode();
            if (this.Buffer != null)
                result ^= this.Buffer.GetHashCode();
            if (this.Labeling != null)
                result ^= this.Labeling.GetHashCode();
            return result;
        }
    }

    public partial class Spectrometer
    {
        public override int GetContentHashCode()
        {
            int result = base.GetContentHashCode();
            result ^= this.Frequency.GetHashCode();
            return result;
        }
    }

    public partial class NMRObject
    {
        public override int GetContentHashCode()
        {
            int result = base.GetContentHashCode();
            if (this.Content != null)
                result ^= this.Content.GetHashCode();

            foreach (NumberedAuthor nA in this.Authors.Where(aa => aa.Index >= 0))
            {
                result ^= nA.User.Username.GetHashCode();
                result ^= nA.Index.GetHashCode();
            }

            return result;
        }
    }

    public partial class Script
    {
        public override int GetContentHashCode()
        {
            int result = base.GetContentHashCode();
            if (this.Type != null)
                result ^= this.Type.GetHashCode();

            result ^= this.IsIncludable.GetHashCode();
            return result;
        }
    }

    public partial class PulseProgram
    {
        public override int GetContentHashCode()
        {
            int result = base.GetContentHashCode();
            result ^= this.Dimensionality.GetHashCode();
            if (this.Analytics != null)
                result ^= this.Analytics.GetHashCode();

            if (this.Type != null)
                result ^= this.Type.GetHashCode();

            foreach (NamedComponent nC in this.AuxComponents)
            {
                result ^= nC.Identifier.GetHashCode();
                result ^= nC.AuxComponent.Id.GetHashCode();
            }

            return result;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public partial class BaseObject  //: IEquatable<BaseObject>
    // commented methods are to demonstrate how one could implement interface
    // but since logic requires to compare not only objects itself but the character of 
    // relations we do not want to include it into default equatable logic since
    // default object comparison is used in some other content where relations are not only not loaded
    // but the mechanizm is not initiated
    // hence the ContentEquals method
    {
        public virtual int GetContentHashCode()
        {
            int result = 0;
            if (this.Script != null)
                result ^= this.Script.GetHashCode();
            if (this.Name != null)
                result ^= this.Name.GetHashCode();
            if (this.Info != null)
                result ^= this.Info.GetHashCode();
            return result;
        }

        //public override bool Equals(object obj)
        //{
        //    if (!(obj is BaseObject))
        //        throw new InvalidCastException("The 'obj' argument is not of a BaseObject type.");
        //    else
        //        return this.Equals(obj as BaseObject);
        //}

        /// <summary>
        /// Checks if user defined fields are equal. Based on GetHashCode(), which must be overriden
        /// to include extra fields and related items.
        /// </summary>
        /// <param name="other"></param>
        /// <returns>True, if objects itentical, false - if not.</returns>
        public bool ContentEquals(BaseObject other)
        {
            //if (object.ReferenceEquals(other, null)) return false;
            if (other == null) return false;
            return this.GetContentHashCode() == other.GetContentHashCode();
        }

        //public static bool operator ==(BaseObject obj1, BaseObject obj2)
        //{
        //    if (object.ReferenceEquals(obj1, null)) return object.ReferenceEquals(obj2, null);
        //    return obj1.Equals(obj2);
        //}

        //public static bool operator !=(BaseObject obj1, BaseObject obj2)
        //{
        //    if (object.ReferenceEquals(obj1, null))
        //        return (!object.ReferenceEquals(obj2, null));
        //    return (!obj1.Equals(obj2));
        //}
    }
}
